/******************************************************************************
 * Filename : uc_buf.h
 * Created  : 2009-10-01 by franco.yin
 * Description -
 * 
 ******************************************************************************/

#ifndef	__UC_BUF_H__
#define	__UC_BUF_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "uc_public.h"
#include "uc_socket.h"
#include "uc_list.h"
#include "uc_hash.h"

#define UCBUF_HUGE_LEN		(500 * 1024)
#define UCBUF_LARGE_LEN		(50 * 1024)
#define UCBUF_SMALL_LEN		(3 * 1024)

#define UCBUF_MAGIC			9527

typedef struct ucbuf {
	ucnode_s node_list;
	uchash_node_s node_hash;
	int size;
	int magic;
	char *memory;
	char *sendp, *recvp;
	char *headp, *endp;
}ucbuf_s;

#define ucbuf_struct(name, l)					\
	char ucbuf##name##tmp[(l)+sizeof(ucmsg_s)];		\
	ucbuf_s name = {					\
		{NULL, NULL,},{{NULL, NULL,},{NULL, NULL,},},							\
		(l)+sizeof(ucmsg_s),			\
		UCBUF_MAGIC,				\
		ucbuf##name##tmp, 		\
		ucbuf##name##tmp, 		\
		ucbuf##name##tmp, 		\
		ucbuf##name##tmp + sizeof(ucmsg_s),	\
		ucbuf##name##tmp + sizeof(ucmsg_s),	\
	}

#define ucbuf_huge(name)			ucbuf_struct(name, UCBUF_HUGE_LEN)
#define ucbuf_large(name)			ucbuf_struct(name, UCBUF_LARGE_LEN)
#define ucbuf_small(name)			ucbuf_struct(name, UCBUF_SMALL_LEN)
#define ucbuf_packet(name)		ucbuf_struct(name, UC_MAX_PACKET_DATA_LEN)

#define ucbuf_len(pBuf)			(int)((pBuf)->endp - ((pBuf)->memory + sizeof(ucmsg_s)))
#define ucbuf_len_send(pBuf)		(int)((pBuf)->endp - (pBuf)->sendp)
#define ucbuf_len_recv(pBuf)		(int)((pBuf)->endp - (pBuf)->recvp)
#define ucbuf_empty(pBuf)			(ucbuf_len(pBuf) == 0)
#define ucbuf_full(pBuf)			(ucbuf_len(pBuf) == (pBuf)->size - sizeof(ucmsg_s))
#define ucbuf_getputp(pBuf)		((pBuf)->endp)
#define ucbuf_getgetp(pBuf)		((pBuf)->headp)
#define ucbuf_getmsgp(pBuf)		((ucmsg_s *)((pBuf)->memory))
#define ucbuf_setmsgp(pBuf, pMsg)					\
	do {							\
		memcpy((pBuf)->memory, (pMsg), sizeof(ucmsg_s));\
	} while (0)

#define ucbuf_getleftsize_recv(pBuf)	((pBuf)->memory + (pBuf)->size	- (pBuf)->recvp)
#define ucbuf_getleftsize(pBuf)	((pBuf)->memory + (pBuf)->size	- (pBuf)->endp)

#define ucbuf_getputpl(pBuf)		((int *)((pBuf)->endp))
#define ucbuf_setputpl(pPut, val)					\
	do {							\
		(*((int *)(pPut)) = htonl(val));\
	} while (0)

#define ucbuf_headp_reset(pBuf)					\
	do {							\
		(pBuf)->headp = (pBuf)->memory + sizeof(ucmsg_s);\
	} while (0)

#define ucbuf_reset(pBuf)					\
	do {							\
		(pBuf)->sendp = (pBuf)->recvp = (pBuf)->memory;	\
		(pBuf)->headp = (pBuf)->endp = (pBuf)->memory + sizeof(ucmsg_s);	\
	} while (0)

#define ucbuf_copy(bufp1, bufp2)				\
	do {							\
		int	len; 					\
		len = uc_min(ucbuf_getputsize(bufp1), 		\
				ucbuf_len(bufp2));		\
		memcpy((bufp1)->endp, (bufp2)->headp, len);	\
		(bufp1)->endp += len;				\
	} while (0)

#define ucbuf_putc(pBuf, c) 					\
	do {							\
		char d = (c);					\
		ucbuf_put((pBuf), &d, sizeof(d));		\
	} while (0)

#define ucbuf_getc(pBuf, c) 					\
	do {							\
		char d = 0;					\
		ucbuf_get((pBuf), &d, sizeof(d));		\
		(c) = d;					\
	} while (0)

#define ucbuf_puts(pBuf, s) 					\
	do {							\
		UC_U16 d = htons(s);				\
		ucbuf_put((pBuf), (char *)&d, sizeof(d));	\
	} while (0)

#define ucbuf_gets(pBuf, s) 					\
	do {							\
		UC_U16 d = 0;					\
		ucbuf_get((pBuf), (char *)&d, sizeof(d));	\
		(s) = ntohs(d);					\
	} while (0)

#define ucbuf_putl(pBuf, l) 					\
	do {							\
		UC_U32 d = htonl(l);				\
		ucbuf_put((pBuf), (char *)&d, sizeof(d));	\
	} while (0)

#define ucbuf_getl(pBuf, l) 					\
	do {							\
		UC_U32 d = 0;					\
		ucbuf_get((pBuf), (char *)&d, sizeof(d));	\
		(l) = ntohl(d);					\
	} while (0)

#define ucbuf_putll(pBuf, ll) 					\
	do {							\
		UC_U64 d = htonll(ll);			\
		ucbuf_put((pBuf), (char *)&d, sizeof(d));	\
	} while (0)

#define ucbuf_getll(pBuf, ll) 					\
	do {							\
		UC_U64 d = 0;				\
		ucbuf_get((pBuf), (char *)&d, sizeof(d));	\
		(ll) = ntohll(d);				\
	} while (0)

#define ucbuf_putnstr(pBuf, n, str) 				\
	do {							\
		int len;					\
		if(n <= 0) {				\
			ucbuf_putl((pBuf), 0);			\
		} else {							\
			len = strlen(str);				\
			if (len >= n) { 				\
				len = n - 1;				\
				uc_err("buf invalid string in %s.%d\n", __FILE__, __LINE__);	\
			}						\
			ucbuf_putl((pBuf), len);			\
			ucbuf_put((pBuf), (str), len);		\
		}							\
	} while (0)
	
#define ucbuf_getnstr(pBuf, n, str) 				\
	do {							\
		int len = 0;					\
		int real_len;					\
		ucbuf_getl((pBuf), real_len);			\
		if((n) > 0) {\
			len = uc_min(real_len, ((n) - 1));\
			if(len > 0) {				\
				ucbuf_get((pBuf), (str), len); \
				if (real_len >= (n)) {		\
					ucbuf_jump((pBuf), real_len - len); \
					uc_err("invalid string(%d) in %s.%d\n", real_len, __FILE__, __LINE__); \
				}		\
			}			\
		} else {\
			ucbuf_jump((pBuf), real_len); \
		}\
		(str)[len] = '\0';				\
	} while (0)
		
#define ucbuf_putname(pBuf, name)	ucbuf_putnstr(pBuf, UC_BUF_LEN, name)
#define ucbuf_getname(pBuf, name)	ucbuf_getnstr(pBuf, UC_BUF_LEN, name)

#define ucbuf_putticket(pBuf, ticket) 	            \
    do {							                \
    	ucbuf_put((pBuf), ticket, USER_TICKET_LEN);	\
    } while (0)

#define ucbuf_getticket(pBuf, ticket) 	            \
    do {							                \
    	ucbuf_get((pBuf), ticket, USER_TICKET_LEN); \
    } while (0)


#define ucput_char(p, c) 					\
	do {							\
		char d = (c);					\
		memcpy(p, &d, sizeof(d));		\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucget_char(p, c) 					\
	do {							\
		char d = 0;					\
		memcpy(&d, p, sizeof(d));		\
		(c) = d;				\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucput_short(p, s) 					\
	do {							\
		UC_U16 d = htons(s);				\
		memcpy((p), (char *)&d, sizeof(d));	\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucget_short(p, s) 					\
	do {							\
		UC_U16 d = 0;					\
		memcpy((char *)&d, (p), sizeof(d));	\
		(s) = ntohs(d);					\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucput_long(p, l) 					\
	do {							\
		UC_U32 d = htonl(l);				\
		memcpy((p), (char *)&d, sizeof(d));	\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucget_long(p, l) 					\
	do {							\
		UC_U32 d = 0;					\
		memcpy((char *)&d, (p), sizeof(d));	\
		(l) = ntohl(d);					\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucput_ll(p, l) 					\
	do {							\
		UC_U64 d = htonll(l); 			\
		memcpy((p), (char *)&d, sizeof(d));	\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucget_ll(p, l) 					\
	do {							\
		UC_U64 d = 0; 				\
		memcpy((char *)&d, (p), sizeof(d));	\
		(l) = ntohll(d);					\
		(p) = (char *)(p) + sizeof(d);		\
	} while (0)

#define ucput_mem_len(p, m, len) 					\
	do {							\
		ucput_long((p), (len));				\
		memcpy((void *)(p), (void *)(m), (len));	\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucput_mem(p, m, len) 					\
	do {							\
		memcpy((void *)(p), (void *)(m), (len));	\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucput_mem_zero(p, len) 					\
	do {							\
		memset((void *)(p), 0, (len));	\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucget_mem_len(p, m, len) 					\
	do {							\
		ucget_long((p), (len));				\
		memcpy((void *)(m), (void *)(p), (len));	\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucget_mem(p, m, len) 					\
	do {							\
		memcpy((void *)(m), (void *)(p), (len));	\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucput_str(p, s) 					\
	do {							\
		int	len = strlen(s);			\
		ucput_long((p), len);				\
		memcpy((void *)(p), (void *)(s), len);		\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucget_str(p, s) 					\
	do {							\
		int	len;					\
		ucget_long((p), (len));				\
		if(len > 0) {\
			memcpy((void *)(s), (void *)(p), (len));	\
		}\
		(s)[len] = '\0';				\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucput_nstr(p, n, s) 					\
	do {							\
		int len = strlen(s);			\
		if (len >= n) { 				\
			len = n - 1;				\
			uc_err("buf invalid string in %s.%d\n", __FILE__, __LINE__);	\
		}						\
		ucput_long((p), len);				\
		memcpy((void *)(p), (void *)(s), len);		\
		(p) = (char *)(p) + (len);		\
	} while (0)

#define ucget_nstr(p, n, s) 					\
	do {							\
		int len = 0;					\
		int real_len;					\
		ucget_long((p), real_len);			\
		if((n) > 0) {\
			len = uc_min((int)(n) - 1, real_len);\
			if(len > 0) {\
				memcpy((void *)(s), (void *)(p), (len));	\
			}\
		}\
		(s)[len] = '\0';				\
		(p) = (char *)(p) + real_len;		\
	} while (0)

/* uc_buf.c */
extern ucbuf_s *ucbuf_new(int size);
extern void ucbuf_set_type(ucbuf_s *pBuf, UC_U32 type);
extern int ucbuf_free(ucbuf_s *pBuf);
extern int ucbuf_init(ucbuf_s *pBuf, ucmsg_s *pMsg, int buf_len, int used_len);
extern int ucbuf_jump(ucbuf_s *pBuf, int len);
extern int ucbuf_put(ucbuf_s *pBuf, char *mem, int len);
extern int ucbuf_move(ucbuf_s *pBuf, int len);
extern int ucbuf_get(ucbuf_s *pBuf, char *mem, int len);
extern int ucbuf_insert(ucbuf_s *pBuf, int offset, char *mem, int len);
extern int ucbuf_dump(char *title, ucbuf_s *pBuf);
extern int ucbuf_send_msg(int fd, ucbuf_s *pBuf, int timeout_ms);
extern int ucbuf_sendto_msg(int fd, ucbuf_s *pBuf, SA_IN *dest);
extern int ucbuf_recv_msg(int fd, ucbuf_s *pBuf, int timeout_ms);
extern int ucbuf_recvfrom_msg(int fd, ucbuf_s *pBuf, SA_IN *from);
extern ucbuf_s *ucbuf_recv_new_msg(int fd, int timeout_ms);
extern int ucbuf_send_recv_msg(int fd, ucbuf_s *pBuf, int timeout_ms);
extern void ucbuf_clean_msg_list(uclist_s *pList);

#ifdef __cplusplus
}
#endif

#endif

